package ThematicModelProto;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class ThematicModelBuilder{
	
	public ArrayList<Theme> themes = new ArrayList<Theme>();
	public ArrayList<Motif> motifs = new ArrayList<Motif>();
	public ArrayList<Natom> natoms = new ArrayList<Natom>();
	private Integer noise = 1;

	
	public static void main(String args[]){
		String outputFile = "results.xml";
		Integer noise = 1;
		String themesFolder = ThematicModelBuilder.class.getProtectionDomain().getCodeSource().getLocation().getPath();
		themesFolder = themesFolder.replace("tmb.jar", "")+"themes/";//because java is shit this returns something different if its in a jar file.
		boolean brief = false;
		
		try {
			Integer selectionSize = new Integer(args[1]);
			
			ArrayList<String> themeNames = new ArrayList<String>(); 
			for(int i=2; i<args.length; i++){
				if(args[i].equals("-noise")){
					i++;
					noise = new Integer(args[i]);
				}else if(args[i].equals("-o")){
					i++;
					outputFile = args[i];
				}else if(args[i].equals("-t")){
					i++;
					themesFolder = args[i];
				}else if(args[i].equals("-brief")){
					brief = true;
				}else{
					themeNames.add(args[i]);
				}
			}
			
			
			ThematicModelBuilder tmb = new ThematicModelBuilder(themeNames, themesFolder, noise);
			tmb.loadFabula(args[0]);
			ArrayList<Natom> natoms = tmb.getStorySelection();
			String output = "";
			if(brief){
				output = tmb.selectionToBriefList(natoms, selectionSize);
			}else{
				Document natomsDOM = tmb.selectionToXML(natoms, selectionSize); 
				output = Helpers.xmlToString(natomsDOM);
			}
			
			if(outputFile.equals("-")){
				System.out.println(output);
			}else{
				try {
			        BufferedWriter out = new BufferedWriter(new FileWriter(outputFile));
			        out.write(output);
			        out.close();
			    } catch (IOException e) {
			    	System.err.println(e);
			    }
			}
			
		    if(noise>1){
		    	System.err.println("...Record successfully written.");
		    }
		}catch(Exception e){
			System.err.println(ThematicModelBuilder.getHelp());
		}
		
		
	}
	
	
	public ThematicModelBuilder(ArrayList<String> themes, String foldername, int noise){
		this.noise = noise;
		
		if(noise > 1){
			System.err.println("New Thematic Mode Builder started");
		}
		
		for(String themeName:themes){
			Theme theme = new Theme(themeName, foldername);
			this.themes.add(theme);
			theme.getAllMotifs(this.motifs);
		}
		
	}
	
	public ThematicModelBuilder(ArrayList<String> themes,String foldername){
		this(themes, foldername, 1);
	}
	
	public void loadFabula(String fabulaFile){
		if(noise > 1){
			System.err.println("Loading Fabula from: "+fabulaFile+" ...");
		}

		Document doc = Helpers.parseXmlFile(fabulaFile);
		
		NodeList natomElements = doc.getElementsByTagName("natom");
		
		for(int i = 0; i<natomElements.getLength(); i++){
			NodeList natomChildren = natomElements.item(i).getChildNodes();
			String id ="";
			String url ="";
			String author="";
			HashSet<String> tags = new HashSet<String>();
			for(int k = 0; k<natomChildren.getLength(); k++){
				Node nn = natomChildren.item(k);
				String nname = nn.getNodeName();
				String value = nn.getTextContent();
				if(nname.equals("id")){ id=value; }
				if(nname.equals("url")){ url=value; }
				if(nname.equals("author")){ author=value; }
				if(nname.equals("tags")){
					NodeList tnl = nn.getChildNodes();
					for(int t = 0; t<tnl.getLength(); t++){
						Node tn = tnl.item(t);
						if(tn.getNodeName().equals("tag"))
							tags.add(tn.getTextContent());
					}
				}
			}
			natoms.add(new Natom(id, url, tags, author));
		
		}
		
		if(noise > 1){
			System.err.println("... Loaded Fabula");
		}
		
	}
	
	public HashMap<String, Integer> compileMotifListfoo(Theme theme){
		
		HashMap<String, Integer> compiledList = new HashMap<String, Integer>();

		if(noise > 3){
			System.err.println("Building motif list for "+theme.getName()+"...");
		}
		
		ArrayList<Motif> unpacked = new ArrayList<Motif>(); 
		theme.getAllMotifs(unpacked);
		
		for(int i =0; i<unpacked.size(); i++){
			
			if(compiledList.containsKey(unpacked.get(i).getName())){
				compiledList.put(unpacked.get(i).getName(), new Integer(compiledList.get(unpacked.get(i).getName()).intValue()+1));
			}
			else{
				compiledList.put(unpacked.get(i).getName(), new Integer(1));			
			}
		}
				
		return compiledList;
			
	}

	public double calculateComponentCoverage(ArrayList<Theme> themes, Natom natom){
		double componentsCovered = 0;
		ArrayList<Motif> motifs = new ArrayList<Motif>();
		ArrayList<Theme> subthemes = new ArrayList<Theme>();
		
		for(Theme theme: themes){
			motifs.addAll(theme.getChildMotifs());
			subthemes.addAll(theme.getChildThemes());
		}
		
		for(Motif motif: motifs){
			for(String tag: natom.getFeatures()){
				if(motif.getFeatures().contains(tag)){
					componentsCovered++;
				}
			}
		}
		componentsCovered += calculateThematicCoverage(subthemes, natom)*subthemes.size();
		
		return componentsCovered/(motifs.size()+subthemes.size());
	}

	public boolean motifsAreCovered(ArrayList<Motif> motifs, Natom natom){
		HashSet<String> features = new HashSet<String>();
		for(Motif motif:motifs){
			features.addAll(motif.getFeatures());
		}
		for(String tag:natom.getFeatures()){
			if(features.contains(tag)){
				return true;
			}
		}
		return false;
	}
	
	public double calculateThematicCoverage(ArrayList<Theme> themes, Natom natom){
		double themesMatched = 0;
		for(Theme theme: themes){
			ArrayList<Motif> motifs = new ArrayList<Motif>();
			theme.getAllMotifs(motifs);
			if(motifsAreCovered(motifs, natom)){
				themesMatched++;
			}
		}
		return themesMatched/themes.size();
	}

	public ArrayList<Natom> getStorySelection() {
		
		for(Natom natom:this.natoms){

			natom.thematicScore=calculateThematicCoverage(this.themes, natom);
			
			natom.componentScore=calculateComponentCoverage(this.themes, natom);
			
			natom.score = new Double((natom.thematicScore/2)+(natom.componentScore/2));

		}
		
		Collections.sort(this.natoms);
		
		return this.natoms;
		
	}
	

	
	
	public Document selectionToXML(ArrayList<Natom> natoms, int size){
		
		Document doc = Helpers.db.newDocument();
		
		System.out.println("Writing record xml...");

		//output+="<evallib name='"+name+"'> \n";
		
		//TODO may add this stuff back in but im not currently convinced its necessary and it makes the method header ugly
		/*output+="\t<collection fabula='"+fkeyword+"' fabulasize='"+fsize+"' colsize='"+size+"'> \n";
		output+="\t\t<themes> \n";
		for(int i =0; i<themes.size(); i++){
			output+="\t\t\t<theme>"+themes.get(i).getName()+"</theme> \n";			
		}
		output+="\t\t</themes> \n";
		*/

		Element natomsDOM = doc.createElement("natoms");
		doc.appendChild(natomsDOM);
		for(int i = 0; i<size; i++){
			natomsDOM.appendChild(natoms.get(i).toXML(doc));
		}

		return doc;
		//System.out.println("Writing xml to file D:\\PhD\\Thematics\\evaluation\\Evaluation2\\Records\\"+name+".rec ...");
	}

	public String selectionToBriefList(ArrayList<Natom> natoms, int size){
		String list = "";
		for(int i = 0; i<size; i++){
			list += natoms.get(i).getURL()+"\n";
		}
		return list;
	}
	
	public static String getHelp() {
		String help = "Thematic Model Builder Usage:\n";
		help += "\t tmb <fabula_file> <selection_size> <theme> [theme, theme, ...] [-o output_file] [-t theme_directory] [-noise int] [-brief]";
		return help;
	}
	
	
}
